/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.wsinfra.wsr.impl;

import javax.xml.namespace.QName;

import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;

import cgl.narada.wsinfra.exception.WsFaultException;
import cgl.narada.wsinfra.schemas.soap.BodyType;
import cgl.narada.wsinfra.schemas.soap.EnvelopeDocument;
import cgl.narada.wsinfra.schemas.soap.EnvelopeType;
import cgl.narada.wsinfra.schemas.soap.HeaderType;
import cgl.narada.wsinfra.schemas.wsr.PollRequestDocument;
import cgl.narada.wsinfra.schemas.wsr.RequestDocument;
import cgl.narada.wsinfra.schemas.wsr.ResponseDocument;
import cgl.narada.wsinfra.util.QNameLocator;
import cgl.narada.wsinfra.wsr.WsrNodeUtils;
import cgl.narada.wsinfra.wsr.WsrQNames;
/** 
    This is a utility class which faciliates the retrieval of elements 
    pertaining to WSRM that reside in the SOAP enevelope.
    
    @author Sima Patel
    $Date: 2005/05/04 18:05:34 $
    $Revision: 1.9 $
*/


public class WsrNodeUtilsImpl implements WsrNodeUtils  {
    private static final WsrNodeUtils instance = new WsrNodeUtilsImpl();
    private QNameLocator qNameLocator;
    private WsrQNames wsrQNames;
    private WsrFaultsImpl wsrFaultsImpl;
    private String moduleName = "WsrNodeUtils: ";

    private WsrNodeUtilsImpl() {
        wsrQNames = WsrQNames.getInstance();
        wsrFaultsImpl = WsrFaultsImpl.getInstance();
        qNameLocator = QNameLocator.getInstance();
    }
    public static WsrNodeUtils getInstance() {
        return instance;
    }
    /** Retrieves Request Element from the Header of the SOAP message */
    public RequestDocument getRequestDocument(EnvelopeDocument envelopeDocument)
                           throws WsFaultException {
      
        HeaderType headerType = getEnvelopeHeader(envelopeDocument);
        XmlCursor headerCursor = headerType.newCursor();
        QName requestQName = wsrQNames.getRequest();
        checkForElement(headerCursor, requestQName);
        boolean creationProblems = false;
        RequestDocument requestDocument = null;
        String faultReason ="Problems parsing Request element.\n";
        try {
            requestDocument =
                         RequestDocument.Factory.parse(headerCursor.xmlText());
        } catch (XmlException xmlEx) {
            creationProblems = true;
            faultReason += xmlEx.toString();
        }
        headerCursor.dispose();
        if (requestDocument == null || creationProblems) {
            throwInvalidMessageFault(faultReason);
        }
        return requestDocument;
    }
  
    /** Retrieves PollRequest Element from the Header of the SOAP message. */
    public PollRequestDocument getPollRequestDocument(
                                              EnvelopeDocument envelopeDocument)
                               throws WsFaultException {
        HeaderType headerType = getEnvelopeHeader(envelopeDocument);
        XmlCursor headerCursor = headerType.newCursor();
        QName pollRequestQName = wsrQNames.getPollRequest();
        checkForElement(headerCursor, pollRequestQName);
        boolean creationProblems = false;
        PollRequestDocument pollRequestDocument = null;
        String faultReason ="Problems parsing PollRequest element.\n";
        try {
            pollRequestDocument =
                      PollRequestDocument.Factory.parse(headerCursor.xmlText());
        } catch (XmlException xmlEx) {
            creationProblems = true;
            faultReason += xmlEx.toString();
        }
        headerCursor.dispose();
        if (pollRequestDocument == null || creationProblems) {
            throwInvalidMessageFault(faultReason);
        }
        return pollRequestDocument;
    }
    /** Retrieves Response Element from the Header of the SOAP message. */
    public ResponseDocument getResponseDocument(
                                              EnvelopeDocument envelopeDocument)
                            throws WsFaultException {
        HeaderType headerType = getEnvelopeHeader(envelopeDocument);
        XmlCursor headerCursor = headerType.newCursor();
        QName responseQName = wsrQNames.getResponse();
        checkForElement(headerCursor, responseQName);
        boolean creationProblems = false;
        ResponseDocument responseDocument = null;
        String faultReason ="Problems parsing Response element.\n";
        try {
            responseDocument =
                         ResponseDocument.Factory.parse(headerCursor.xmlText());
        } catch (XmlException xmlEx) {
            creationProblems = true;
            faultReason += xmlEx.toString();
        }
        headerCursor.dispose();
        if (responseDocument == null || creationProblems) {
            throwInvalidMessageFault(faultReason);
        }
        return responseDocument;
    }
  
    /** Retrieves GroupId Element from the Header of the SOAP message */
    public String getGroupId(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
        HeaderType headerType = getEnvelopeHeader(envelopeDocument);
        XmlCursor headerCursor = headerType.newCursor();
        QName groupIdQName = wsrQNames.getGroupId();
        boolean foundQName = qNameLocator.locateQName(headerCursor, groupIdQName);
        if (!foundQName){
            return null;
        }
        String groupId = headerCursor.getTextValue();
        headerCursor.dispose();
        if (groupId == null) {
            return null;
        }
        return groupId;      
    }
    /** Retrieves Group Expiry Time element from the Header of the SOAP Message */
    public String getGroupExpiryTime(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
        HeaderType headerType = getEnvelopeHeader(envelopeDocument);
        XmlCursor headerCursor = headerType.newCursor();
        QName groupExpiryTimeQName = wsrQNames.getGroupExpiryTime();
        boolean foundQName = qNameLocator.locateQName(headerCursor, 
                                                      groupExpiryTimeQName);
        if (!foundQName){
           return null;
        }
        String groupExpiryTime = headerCursor.getTextValue();
        headerCursor.dispose();
        if (groupExpiryTime == null) {
           return null;
        }
        return groupExpiryTime;     
    }
    /** Retrieves Group Max Idle Duration element from the Header of the SOAP Message */
    public String getGroupMaxIdleDuration(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
	    HeaderType headerType = getEnvelopeHeader(envelopeDocument);
	    XmlCursor headerCursor = headerType.newCursor();
	    QName groupMaxIdleDurationQName = wsrQNames.getGroupMaxIdleDuration();
	    boolean foundQName = qNameLocator.locateQName(headerCursor, 
	                                                  groupMaxIdleDurationQName);
	    if (!foundQName){
	       return null;
	    }
	    String groupMaxIdleDuration = headerCursor.getTextValue();
	    headerCursor.dispose();
	    if (groupMaxIdleDuration == null) {
	       return null;
	    }
	    return groupMaxIdleDuration;          
	    	
    }
    /** Retrieves Message Expiry Time element from the Header of the SOAP Message */
    public String getMExpiryTime(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
    	HeaderType headerType = getEnvelopeHeader(envelopeDocument);
	    XmlCursor headerCursor = headerType.newCursor();
	    QName mExpiryTimeQName = wsrQNames.getMExpiryTime();
	    boolean foundQName = qNameLocator.locateQName(headerCursor, mExpiryTimeQName);
	    if (!foundQName){
	       return null;
	    }
	    String messageExpiryTime = headerCursor.getTextValue();
	    headerCursor.dispose();
	    if (messageExpiryTime == null) {
	       return null;
	    }
	    return messageExpiryTime;
    	
    }
    /** Retrieves Reply Pattern element from the Header of the Soap Message */
    public String getRPattern(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
    	HeaderType headerType = getEnvelopeHeader(envelopeDocument);
	    XmlCursor headerCursor = headerType.newCursor();
	    QName rPatternQName = wsrQNames.getRPattern();
	    boolean foundQName = qNameLocator.locateQName(headerCursor, rPatternQName);
	    if (!foundQName){
	       return null;
	    }
	    String replyPattern = headerCursor.getTextValue();
	    headerCursor.dispose();
	    if (replyPattern == null) {
	       return null;
	    }
	    return replyPattern;
    	
    }
    /** Retrieves last Message element from the Header of the SOAP Message */
    public String getLastMessage(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
    	HeaderType headerType = getEnvelopeHeader(envelopeDocument);
	    XmlCursor headerCursor = headerType.newCursor();
	    QName lastMessageQName = wsrQNames.getLastMessage();
	    boolean foundQName = qNameLocator.locateQName(headerCursor, lastMessageQName);
	    if (!foundQName){
	       return null;
	    }
	    String lastMessage = headerCursor.getTextValue();
	    headerCursor.dispose();
	    if (lastMessage == null) {
	       return null;
	    }
	    return lastMessage;
    	
    }
    /** Retrieves replyTo element from the Header of the SOAP Message */
    public String getReplyTo(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
    	HeaderType headerType = getEnvelopeHeader(envelopeDocument);
	    XmlCursor headerCursor = headerType.newCursor();
	    QName replyToQName = wsrQNames.getReplyTo();
	    boolean foundQName = qNameLocator.locateQName(headerCursor, replyToQName);
	    if (!foundQName){
	       return null;
	    }
	    String replyTo = headerCursor.getTextValue();
	    headerCursor.dispose();
	    if (replyTo == null) {
	       return null;
	    }
	    return replyTo;
    }
    /** Retrieves Message Exchange Pattern from the Header of the SOAP Message */
    public String getMessageExchangePattern(EnvelopeDocument envelopeDocument)
                  throws WsFaultException{
    	HeaderType headerType = getEnvelopeHeader(envelopeDocument);
        XmlCursor headerCursor = headerType.newCursor();
        QName messageExchangePatternQName = wsrQNames.getMessageExchangePattern();
        boolean foundQName = qNameLocator.locateQName(headerCursor, 
        		                                      messageExchangePatternQName);
        if (!foundQName){
            return null;
        }
        String messageExchangePattern = headerCursor.xmlText();
        headerCursor.dispose();
        if (messageExchangePattern == null) {
            return null;
        }
        return messageExchangePattern;   
    }
    /** Check to see if the element exists and position the cursor at the
    right location if it does */
    private void checkForElement(XmlCursor xmlCursor, QName qName)
                 throws WsFaultException {

        String faultReason = "";
        boolean foundQName = qNameLocator.locateQName(xmlCursor, qName);
        if (!foundQName) {
            xmlCursor.dispose();
            faultReason = "Unable to Locate element [" + qName +
            "], no further processing possible.";
            throwInvalidMessageFault(faultReason);
        }
    }
    /** Checks whether MessageID element exists or not*/
    public boolean hasMessageIDElement(RequestDocument requestDocument){
    	XmlCursor messageIdCursor = requestDocument.getRequest().newCursor();
        QName messageIdQName = wsrQNames.getMessageId();
        boolean hasMessageId = qNameLocator.locateQName(messageIdCursor, 
                                                                messageIdQName);
        messageIdCursor.dispose();
        return hasMessageId;               
    }
    
    /** Checks whether GroupId Attribure to MessageId Element exists or not*/
    public boolean hasGroupId(RequestDocument requestDocument){
    	XmlCursor messageIdCursor = requestDocument.getRequest().newCursor();
        QName messageIdQName = wsrQNames.getMessageId();
        boolean hasMessageId = qNameLocator.locateQName(messageIdCursor, messageIdQName);
        if(messageIdCursor.toFirstAttribute()){
        	messageIdCursor.dispose();
        	return true;
        }else{
        	messageIdCursor.dispose();
        	return false;
        }
    	
    }
    /** Checks whether ExpiryTime element exists or not*/
    public boolean hasMessageExpiryTimeElement(RequestDocument requestDocument){
    	XmlCursor messageExpiryTimeCursor = requestDocument.getRequest().newCursor();
        QName messageExpiryTimeQName = wsrQNames.getExpiryTime();
        boolean hasMessageExpiryTime = qNameLocator.locateQName(messageExpiryTimeCursor,
        		                                                messageExpiryTimeQName);
        messageExpiryTimeCursor.dispose();
        return hasMessageExpiryTime;   
    }
    
    /** Checks whether ReplyPattern element exists or not*/
    public boolean hasReplyPatternElement(RequestDocument requestDocument){
    	XmlCursor replyPatternCursor = requestDocument.getRequest().newCursor();
        QName replyPatternQName = wsrQNames.getReplyPattern();
        boolean hasReplyPattern = qNameLocator.locateQName(replyPatternCursor,
        		                                           replyPatternQName);
        replyPatternCursor.dispose();
        return hasReplyPattern;   
    }
    
    /** Checks whether RefToMessageIds element exists or not */
    public boolean hasRefToMessageIdsElement(PollRequestDocument pollRequestDocument){
    	XmlCursor refToMessageIdsCursor = pollRequestDocument.getPollRequest().newCursor();
        QName refToMessageIdsQName = wsrQNames.getRefToMessageIds();
        boolean hasRefToMessageIds = qNameLocator.locateQName(refToMessageIdsCursor,
        													  refToMessageIdsQName);
        refToMessageIdsCursor.dispose();
        return hasRefToMessageIds;  
    	
    }
    /** Checks for problems with the envelope and returns the envelope body */
    private BodyType getEnvelopeBody(EnvelopeDocument envelopeDocument)
                     throws WsFaultException {
        String faultReason = "";
        if (envelopeDocument == null) {
            faultReason = "The specified envelope is NULL";
            throwInvalidMessageFault(faultReason);
        }
        BodyType bodyType = envelopeDocument.getEnvelope().getBody();
        if (bodyType == null) {
            faultReason = "The body of SOAP message is NULL!";
            throwInvalidMessageFault(faultReason);
        }
        return bodyType;
    }

    /** Checks for problems with the envelope and returns the envelope Header */
    private HeaderType getEnvelopeHeader(EnvelopeDocument envelopeDocument)
                       throws WsFaultException {
        String faultReason = "";
        if (envelopeDocument == null) {
            faultReason = "The specified envelope is NULL";
            throwInvalidMessageFault(faultReason);
        }
        EnvelopeType envelope = envelopeDocument.getEnvelope();
        if (!envelope.isSetHeader()) {
            faultReason = "This SOAP message DOES NOT have a header!";
        }
        HeaderType headerType = envelope.getHeader();
        if (headerType == null) {
            faultReason = "The header of the SOAP message is NULL!";
            throwInvalidMessageFault(faultReason);
        }
        return headerType;
    }
    /** Throw a WsFaultException, initialized with the invalid message QName
    and the specified reason */
    private void throwInvalidMessageFault(String reason)
                 throws WsFaultException {

        WsFaultException wsFaultException = 
               new WsFaultException(wsrFaultsImpl.getSoapSenderQName(), reason);
        throw wsFaultException;
    }
   
}